package com.example.bigdemo.topomode.service.impl;

import com.example.bigdemo.pojo.Values;
import com.example.bigdemo.sercive.Impl.WalkserviceImpl;
import com.example.bigdemo.sercive.Walkservice;
import com.example.bigdemo.topomode.pojo.portMessageObject;
import com.example.bigdemo.topomode.service.TopoService;
import lombok.extern.slf4j.Slf4j;
import org.snmp4j.*;
import org.snmp4j.event.ResponseEvent;
import org.snmp4j.event.ResponseListener;
import org.snmp4j.mp.MessageProcessingModel;
import org.snmp4j.mp.SnmpConstants;
import org.snmp4j.smi.*;
import org.snmp4j.transport.DefaultUdpTransportMapping;
import org.snmp4j.util.PDUFactory;
import org.snmp4j.util.TableEvent;
import org.snmp4j.util.TableUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.io.IOException;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.TimeUnit;
@Slf4j
@Service
public class ToposerviceImpl implements TopoService {


    public List<portMessageObject> GetPortMessage(String ip) {
        List<portMessageObject> l = new ArrayList();
        int j =0;


        TransportMapping transport = null ;
        Snmp snmp = null ;
        CommunityTarget target;
        String[] IF_OIDS =
                {"1.3.6.1.2.1.2.2.1.1",  //Index
                        "1.3.6.1.2.1.2.2.1.2",  //descr
                        "1.3.6.1.2.1.2.2.1.3",  //type
                        "1.3.6.1.2.1.2.2.1.5",  //speed
                        "1.3.6.1.2.1.2.2.1.6",  //mac
                        "1.3.6.1.2.1.2.2.1.7",  //adminStatus
                        "1.3.6.1.2.1.2.2.1.8",  //operStatus

                        "1.3.6.1.2.1.2.2.1.10", //inOctets
                        "1.3.6.1.2.1.2.2.1.16", //outOctets
                        "1.3.6.1.2.1.2.2.1.14", //inError
                        "1.3.6.1.2.1.2.2.1.20", //outError
                        "1.3.6.1.2.1.2.2.1.13", //inDiscard
                        "1.3.6.1.2.1.2.2.1.19", //outDiscard
                        "1.3.6.1.2.1.2.2.1.11", //inUcastPkts
                        "1.3.6.1.2.1.2.2.1.17", //outUcastPkts
                        "1.3.6.1.2.1.2.2.1.12", //inNUcastPkts
                        "1.3.6.1.2.1.2.2.1.18"};//outNUcastPkts

        try {
            transport = new DefaultUdpTransportMapping();
            snmp = new Snmp(transport);
            snmp.listen();
            target = new CommunityTarget();
            target.setCommunity(new OctetString("public"));
            target.setRetries(2);
            target.setAddress(GenericAddress.parse("udp:"+ip+"/161"));
            target.setTimeout(8000);
            target.setVersion(SnmpConstants.version2c);
            TableUtils tableUtils = new TableUtils(snmp, new PDUFactory() {
                @Override
                public PDU createPDU(Target arg0) {
                    PDU request = new PDU();
                    request.setType(PDU.GET);
                    return request;
                }
                @Override
                public PDU createPDU(MessageProcessingModel messageProcessingModel) {
                    PDU request = new PDU();
                    request.setType(PDU.GET);
                    return request;
                }

            });
            OID[] columns = new OID[IF_OIDS.length];
            for (int i = 0; i < IF_OIDS.length; i++)
                columns[i] = new OID(IF_OIDS[i]);
            @SuppressWarnings("unchecked")
            List<TableEvent> list = tableUtils.getTable(target, columns, null, null);
            if(list.size()==1 && list.get(0).getColumns()==null){
                portMessageObject  p= new portMessageObject(null,null,null);
                l.add(p);
            }else{
                for(TableEvent event : list){
                    portMessageObject  p= new portMessageObject();

                    VariableBinding[] values = event.getColumns();
                    if(values == null) continue;
                    p.setIfdescr(values[1].getVariable().toString());
                    p.setType(values[2].getVariable().toString());
                    p.setIfoperStatus(values[6].getVariable().toString());
//                    variableString.put("interfaceIndex",values[0].getVariable().toString());
//                    variableString.put("descr",values[1].getVariable().toString());
//                    variableString.put("type",values[2].getVariable().toString());
//                    variableString.put("speed",values[3].getVariable().toString());
//                    variableString.put("mac",values[4].getVariable().toString());
//                    variableString.put("adminStatus",values[5].getVariable().toString());
//                    variableString.put("operStatus",values[6].getVariable().toString());

                    l.add(p);
                }
            }


        } catch(Exception e){
            e.printStackTrace();
        }finally{
            try {
                if(transport!=null)
                    transport.close();
                if(snmp!=null)
                    snmp.close();
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
        return l;
    }

    //初始化snmp连接
    public static CommunityTarget createDefault(String ip, String community) {
        Address address = GenericAddress.parse("udp" + ":" + ip
                + "/" + 161);
        CommunityTarget target = new CommunityTarget();
        target.setCommunity(new OctetString(community));
        target.setAddress(address);
        target.setVersion(SnmpConstants.version2c);
        target.setTimeout(3 * 1000L); // milliseconds
        target.setRetries(3);
        return target;
    }


    public static List<Values> Walk(String ip, String community, String oid) {
        List<Values> l = new ArrayList();

        final CommunityTarget target = createDefault(ip, community);
        Snmp snmp = null;
        try {

            DefaultUdpTransportMapping transport = new DefaultUdpTransportMapping();
            snmp = new Snmp(transport);
            snmp.listen();

            final PDU pdu = new PDU();
            final OID targetOID = new OID(oid);
            final CountDownLatch latch = new CountDownLatch(1);
            pdu.add(new VariableBinding(targetOID));

            ResponseListener listener = new ResponseListener() {

                int j = 0;
                Map<String, String> variableString = null;
                Values R = null;
                public void onResponse(ResponseEvent event) {
                    ((Snmp) event.getSource()).cancel(event.getRequest(), this);

                    try {
                        PDU response = event.getResponse();
                        // PDU request = event.getRequest();
                        // System.out.println("[request]:" + request);
                        if (response == null) {
                            System.out.println("[ERROR]: response is null");
                        } else if (response.getErrorStatus() != 0) {
                            System.out.println("[ERROR]: response status"
                                    + response.getErrorStatus() + " Text:"
                                    + response.getErrorStatusText());
                        } else {
                            System.out.println("Received Walk response value :");
                            VariableBinding vb = response.get(0);

                            boolean finished = checkWalkFinished(targetOID, pdu, vb);
                            if (!finished) {
                                variableString =new HashMap<String, String>();
                                R = new Values();
                                System.out.println(vb.getOid() + " = " + vb.getVariable());
                                variableString.put(String.valueOf(vb.getOid()), String.valueOf(vb.getVariable()));
                                R.setNum(j);
                                R.setValue(variableString);
                                j++;
                                l.add(R);

                                pdu.setRequestID(new Integer32(0));
                                pdu.set(0, vb);
                                ((Snmp) event.getSource()).getNext(pdu, target, null, this);
                            } else {

                                latch.countDown();
                            }
                        }
                    } catch (Exception e) {
                        e.printStackTrace();
                        latch.countDown();
                    }

                }
            };

            snmp.getNext(pdu, target, null, listener);

            boolean wait = latch.await(30, TimeUnit.SECONDS);
            System.out.println("latch.await =:" + wait);
            snmp.close();

            System.out.println("---->  end <----");
        } catch (Exception e) {
            e.printStackTrace();
            System.out.println("SNMP  Walk Exception:" + e);
        }
        return l;
    }

    private static boolean checkWalkFinished(OID walkOID, PDU pdu,
                                             VariableBinding vb) {
        boolean finished = false;
        if (pdu.getErrorStatus() != 0) {
            System.out.println("[true] pdu.getErrorStatus() != 0 ");
            System.out.println(pdu.getErrorStatusText());
            finished = true;
        } else if (vb.getOid() == null) {
            System.out.println("[true] vb.getOid() == null");
            finished = true;
        } else if (vb.getOid().size() < walkOID.size()) {
            System.out.println("[true] vb.getOid().size() < targetOID.size()");
            finished = true;
        } else if (walkOID.leftMostCompare(walkOID.size(), vb.getOid()) != 0) {
            System.out.println("[true] targetOID.leftMostCompare() != 0");
            finished = true;
        } else if (Null.isExceptionSyntax(vb.getVariable().getSyntax())) {
            System.out
                    .println("[true] Null.isExceptionSyntax(vb.getVariable().getSyntax())");
            finished = true;
        } else if (vb.getOid().compareTo(walkOID) <= 0) {
            System.out.println("[true] vb.getOid().compareTo(walkOID) <= 0 ");
            finished = true;
        }
        return finished;

    }


    public  List<Values> topoIpWalk(String ip) {
        // 异步采集数据
        List<Values> list = ToposerviceImpl.Walk(ip, "public", ".1.3.6.1.2.1.4.22.1.4.");
        return list;
    }


}
